package main

import (
	"container/list"
	"fmt"
	"strconv"
	"strings"
)

type OrderdMap struct {
	items  *list.List
	Mapper map[string]*list.Element
	fkey   func(item any) string
}

//func newOrderdMap[T any, E any](fkey func(item any) string) interface{} {
//    ASSERT(fkey != nil)
//    return &T{OrderdMap: {
//        items:  list.New(),
//        Mapper: make(map[string]*list.Element),
//        fkey:   fkey,
//    }}
//}

func (p *OrderdMap) Len() int {
	return p.items.Len()
}

func (p *OrderdMap) Foreach(handle func(item any) int) {
	ASSERT(handle != nil)
	for elem := p.items.Front(); elem != nil; elem = elem.Next() {
		if handle(elem.Value) != 0 {
			break
		}
	}
}

func (p *OrderdMap) Exist(name string) bool {
	_, ok := p.Mapper[name]
	return ok
}

func (p *OrderdMap) Find(name string) (*list.Element, bool) {
	elem, ok := p.Mapper[name]
	return elem, ok
}

func (p *OrderdMap) Front() *list.Element {
	return p.items.Front()
}

func (p *OrderdMap) Back() *list.Element {
	return p.items.Front()
}

func (p *OrderdMap) Remove(elem *list.Element) any {
	value := elem.Value
	delete(p.Mapper, p.fkey(value))
	p.items.Remove(elem)
	return value
}

func (p *OrderdMap) RemoveByKey(key string) any {
	elem, ok := p.Mapper[key]
	if !ok {
		return nil
	}

	item := elem.Value

	delete(p.Mapper, p.fkey(item))
	p.items.Remove(elem)
	return item
}

func (p *OrderdMap) PushBack(item any) *list.Element {
	elem := p.items.PushBack(item)
	p.Mapper[p.fkey(item)] = elem
	return elem
}

func (p *OrderdMap) String() string {
	buf := strings.Builder{}
	buf.WriteString("PROP(")
	for item := p.items.Front(); item != nil; item = item.Next() {
		buf.WriteString(p.fkey(item.Value))
		buf.WriteString(";")
	}
	buf.WriteString(")")

	return buf.String()
}

type SignalKind int

const (
	SignalKindSweep = SignalKind(0)
	SignalKindTrace = SignalKind(1)
)

const (
	KindClassifyMask = uint8(0xF0)

	KindClassifyInt     = uint8(0x10)
	KindClassifyFloat   = uint8(0x20)
	KindClassifyComplex = uint8(0x30)
	KindClassifyString  = uint8(0x40)
	KindClassifyArray   = uint8(0x50)
	KindClassifyStruct  = uint8(0x60)
)

const (
	KindRefinedMask = uint8(0x0F)

	KindRefinedByte    = uint8(0x01) // INT BYTE
	KindRefinedShort   = uint8(0x02) // INT SHORT
	KindRefinedLong    = uint8(0x03) // INT LONG
	KindRefinedDouble  = uint8(0x04) // FLOAT DOUBLE 或者 COMPLEX DOUBLE
	KindRefinedPointer = uint8(0x06) // 类似：STRING *
	KindRefinedGroup   = uint8(0x07) // 类似：ARRAY  '(' '*' ')' type
	KindRefinedMember  = uint8(0x08) // 类似：STRUCT '(' EOL (name type prop? EOL)*  ')'
)

type TypeDefinition struct {
	// 类型型别
	Kind uint8

	// 类型的命名
	Name string

	// for array
	ElemType *TypeDefinition

	// for struct
	Members *MemberDefinitions // *MemberDefinition

	Prop *Properties // *Property
}

func (t *TypeDefinition) String() string {
	return fmt.Sprintf("%v %v", t.ClassifyString(), t.RefinedString())
}

func (t *TypeDefinition) ClassifyString() string {
	mapping := map[uint8]string{
		KindClassifyInt:     "INT",
		KindClassifyFloat:   "FLOAT",
		KindClassifyComplex: "COMPLEX",
		KindClassifyString:  "STRING",
		KindClassifyArray:   "ARRAY",
		KindClassifyStruct:  "STRUCT",
	}

	return mapping[t.Kind&KindClassifyMask]
}

func (t *TypeDefinition) RefinedString() string {
	switch t.Kind & KindRefinedMask {
	case KindRefinedByte:
		return "BYTE"
	case KindRefinedShort:
		return "SHORT"
	case KindRefinedLong:
		return "LONG"
	case KindRefinedDouble:
		return "DOUBLE"
	case KindRefinedPointer:
		return "*"
	case KindRefinedGroup:
		return fmt.Sprintf("( * ) %v", t.ElemType.String())
	case KindRefinedMember:
		buf := strings.Builder{}
		buf.WriteString("STRUCT(")
		for elem := t.Members.Front(); elem != nil; elem = elem.Next() {
			buf.WriteString(elem.Value.(*MemberDefinition).String())
			buf.WriteString(";")
		}
		buf.WriteString(")")
		return buf.String()
	}

	ASSERT(false)
	return ""
}

type MemberDefinition struct {
	Name string
	Type *TypeDefinition
	Prop *Properties
}

func NewMemberDefinition() *MemberDefinition {
	return &MemberDefinition{
		Name: "",
		Type: nil,
		Prop: NewProperties(),
	}
}

func (m *MemberDefinition) String() string {
	buf := strings.Builder{}
	buf.WriteString(m.Name)
	buf.WriteString(" ")
	buf.WriteString(m.Type.String())
	if m.Prop.Len() > 0 {
		buf.WriteString("PROP(")
		m.Prop.Foreach(func(item interface{}) int {
			buf.WriteString(item.(*Property).String())
			return 0
		})
		buf.WriteString(")")
	}
	return buf.String()
}

type Property struct {
	Name  string
	Value Value
}

func (p *Property) String() string {
	return fmt.Sprintf("%v %v", p.Name, FormatValue(p.Value))
}

type Properties struct{ OrderdMap }

func NewProperties() *Properties {
	// return newOrderdMap[Properties, Property](func(item *Property) string { return item.Name }).(*Properties)
	return &Properties{OrderdMap{
		items:  list.New(),
		Mapper: make(map[string]*list.Element),
		fkey:   func(item any) string { return item.(*Property).Name },
	}}
}

type TypeDefinitions struct{ OrderdMap }

func NewTypeDefinitions() *TypeDefinitions {
	return &TypeDefinitions{OrderdMap{
		items:  list.New(),
		Mapper: make(map[string]*list.Element),
		fkey:   func(item any) string { return item.(*TypeDefinition).Name },
	}}
}

type MemberDefinitions struct{ OrderdMap }

func NewMemberDefinitions() *MemberDefinitions {
	// return newOrderdMap(func(item any) string { return item.(*MemberDefinition).Name }).(*MemberDefinitions)
	return &MemberDefinitions{OrderdMap{
		items:  list.New(),
		Mapper: make(map[string]*list.Element),
		fkey:   func(item any) string { return item.(*MemberDefinition).Name },
	}}
}

type SignalDefinitions struct{ OrderdMap }

func NewSignalDefinitions() *SignalDefinitions {
	// return newOrderdMap(func(item any) string { return item.(*SignalDefinition).SignalName }).(*SignalDefinitions)
	return &SignalDefinitions{OrderdMap{
		items:  list.New(),
		Mapper: make(map[string]*list.Element),
		fkey:   func(item any) string { return item.(*SignalDefinition).SignalName },
	}}
}

type ValueSequences struct{ OrderdMap }

func NewValueSequences() *ValueSequences {
	// return newOrderdMap(func(item any) string { return item.(*ValueSequence).SignalName }).(*ValueSequences)
	return &ValueSequences{OrderdMap{
		items:  list.New(),
		Mapper: make(map[string]*list.Element),
		fkey:   func(item any) string { return item.(*ValueSequence).SignalName },
	}}
}

type SignalDefinition struct {
	Kind           SignalKind         // sweep / trace
	SignalName     string             // 信号名称
	SignalTypeName string             // 信号类型名
	Children       *SignalDefinitions // 信号组中的信号列表
	SignalType     *TypeDefinition    // 类型
	Props          *Properties        // 属性 *Property
}

type ValueSequence struct {
	SignalName       string              // 名称
	SignalDefinition *SignalDefinition   // 信号定义
	SignalValues     *list.List          // Value
	Prop             map[int]*Properties // 属性 *Property
}

type Value interface{}

func FormatValue(v Value) string {
	switch a := v.(type) {
	case bool:
		return strconv.FormatBool(a)
	case int32:
		return strconv.FormatInt(int64(a), 10)
	case float64:
		return strconv.FormatFloat(a, 'e', 15, 64)
	case complex128:
		return fmt.Sprintf("(%v, %v)", strconv.FormatFloat(real(a), 'e', 15, 64),
			strconv.FormatFloat(imag(a), 'e', 15, 64))
	case string:
		return v.(string)
	case []interface{}:
		buf := strings.Builder{}
		buf.WriteString("(")
		vec := v.([]Value)
		for i := 0; i < len(vec); i++ {
			if i != 0 {
				buf.WriteString(",")
			}
			buf.WriteString(FormatValue(vec[i]))
		}
		buf.WriteString(")")
		return buf.String()
	default:
		return "UNKNOWN_TYPE"
	}

}

type DatasetDocument struct {
	Parent        *DatasetDocument
	FileName      string
	HeaderItems   *Properties        // *Property
	TypeItems     *TypeDefinitions   // *TypeDefinition
	SignalItems   *SignalDefinitions // *SignalDefinition
	SequenceItems *ValueSequences    // *ValueSequence
}

func NewDatasetDocument(fileName string) *DatasetDocument {
	return &DatasetDocument{
		Parent:        nil,
		FileName:      fileName,
		HeaderItems:   NewProperties(),
		TypeItems:     NewTypeDefinitions(),
		SignalItems:   NewSignalDefinitions(),
		SequenceItems: NewValueSequences(),
	}
}

func (d *DatasetDocument) FindType(name string) (*TypeDefinition, bool) {
	elem, ok := d.TypeItems.Find(name)
	if !ok {
		return nil, false
	}

	return elem.Value.(*TypeDefinition), true
}

func (d *DatasetDocument) FindSignal(name string) (*SignalDefinition, bool) {
	elem, ok := d.SignalItems.Find(name)
	if !ok {
		return nil, false
	}

	return elem.Value.(*SignalDefinition), true
}

func (d *DatasetDocument) FindSequence(name string) (*ValueSequence, bool) {
	elem, ok := d.SequenceItems.Find(name)
	if !ok {
		return nil, false
	}

	return elem.Value.(*ValueSequence), true
}

//type AnalysisInst struct {
//	AnalysisType  string
//	DataFile      string
//	Format        string
//	Parent        string
//	SweepVariable []string
//	Description   string
//}
//
//type DatasetDocumentChain struct {
//	HeaderItems map[string]interface{}
//}

func ASSERT(va bool) {
	if !va {
		panic("")
	}
}
